<template>
    <div id="map">
        <div class="MapTool">
            <el-row>
                <el-button type="primary" @click.stop.prevent="measureCtl('Polygon')">面积</el-button>
                <el-button type="success" @click.stop.prevent="measureCtl('LineString')">距离</el-button>
            </el-row>
        </div>
    </div>
</template>

<script>
    //引入依赖
    import {Map, View, Overlay} from 'ol'
    import * as ol from 'ol'
    import VectorSource from 'ol/source/Vector';
    import VectorLayer from 'ol/layer/Vector';
    import Style from 'ol/style/Style';
    import {Fill, Stroke, Circle} from 'ol/style';
    import {OSM} from 'ol/source'
    import TileLayer from 'ol/layer/Tile'
    import {defaults as defaultControls} from 'ol/control.js';
    import Draw from 'ol/interaction/Draw';
    import {Polygon,LineString} from 'ol/geom';
    import * as sphere from 'ol/sphere';
    import {unByKey} from 'ol/Observable';
    /**
     * 当前绘制的要素（Currently drawn feature.）
     * @type {ol.Feature}
     */
    var sketch;
    /**
     * 帮助提示框对象（The help tooltip element.）
     * @type {Element}
     */
    var helpTooltipElement;
    /**
     *帮助提示框显示的信息（Overlay to show the help messages.）
     * @type {ol.Overlay}
     */
    var helpTooltip;
    /**
     * 测量工具提示框对象（The measure tooltip element. ）
     * @type {Element}
     */
    var measureTooltipElement;
    /**
     *测量工具中显示的测量值（Overlay to show the measurement.）
     * @type {ol.Overlay}
     */
    var measureTooltip;
    /**
     *  当用户正在绘制多边形时的提示信息文本
     * @type {string}
     */
    var continuePolygonMsg = 'Click to continue drawing the polygon';
    /**
     * 当用户正在绘制线时的提示信息文本
     * @type {string}
     */
    var continueLineMsg = 'Click to continue drawing the line';
    /**
     * 事件监听
     */
    var listener;
    /**
     * 绘制交互
     */
    let draw;
    export default {
        name: "MeasureControl",
        data() {
            return {
                map: null,
            }
        },
        mounted() {
            //初始化地图
            this.map = new Map({
                target: 'map',//指定挂载dom，注意必须是id
                layers: [
                    new TileLayer({
                        source: new OSM()//加载OpenStreetMap
                    })
                ],
                //配置视图
                view: new View({
                    center: [113.24981689453125, 23.126468438108688], //视图中心位置
                    projection: "EPSG:4326", //指定投影
                    zoom: 12,  //缩放到的级别
                })
            });
        },
        methods:{
            measureCtl(measureType){
                if(draw){
                    //清除掉之前绘制的交互
                    this.map.removeInteraction(draw);
                }
                //定义一个数据源
                this.source = new VectorSource();
                this.vectorLayer = new VectorLayer({
                    source:this.source,
                    style: new Style({
                        fill: new Fill({
                            color: 'rgba(255, 255, 255, 0.2)'
                        }),
                        stroke: new Stroke({
                            color: '#ffcc33',
                            width: 2
                        }),
                        image: new Circle({
                            radius: 7,
                            fill: new Fill({
                                color: '#ffcc33'
                            })
                        })
                    })
                });
                this.map.addLayer(this.vectorLayer);

                //地图容器绑定鼠标移动事件，动态显示帮助提示框内容
                this.map.on('pointermove', this.pointerMoveHandler);

                //根据不同类型添加绘制的交互
                this.addInteraction(measureType)
            },
            pointerMoveHandler(event) {
                if (event.dragging) {
                    return;
                }
                //当前默认提示信息
                var helpMsg = 'Click to start drawing';
                //判断绘制几何类型设置相应的帮助提示信息
                if (sketch) {
                    var geom = (sketch.getGeometry());
                    if (geom instanceof Polygon) {
                        helpMsg = continuePolygonMsg; //绘制多边形时提示相应内容
                    } else if (geom instanceof LineString) {
                        helpMsg = continueLineMsg; //绘制线时提示相应内容
                    }
                }
                helpTooltipElement.innerHTML = helpMsg; //将提示信息设置到对话框中显示
                helpTooltip.setPosition(event.coordinate);//设置帮助提示框的位置
                //$(helpTooltipElement).removeClass('hidden');//移除帮助提示框的隐藏样式进行显示
            },
            /**
             *创建一个新的帮助提示框（tooltip）
             */
            createHelpTooltip() {
                if (helpTooltipElement) {
                    helpTooltipElement.parentNode.removeChild(helpTooltipElement);
                }
                helpTooltipElement = document.createElement('div');
                helpTooltipElement.className = 'tooltip hidden';
                helpTooltip = new Overlay({
                    element: helpTooltipElement,
                    offset: [15, 0],
                    positioning: 'center-left'
                });
                //提示框的覆盖层
                this.map.addOverlay(helpTooltip);
            },
            /**
             *创建一个新的测量工具提示框（tooltip）
             */
            createMeasureTooltip() {
                //重置提示框
                if (measureTooltipElement) {
                    measureTooltipElement.parentNode.removeChild(measureTooltipElement);
                }
                measureTooltipElement = document.createElement('div');
                measureTooltipElement.className = 'tooltip tooltip-measure';
                //提示框的覆盖层
                measureTooltip = new Overlay({
                    element: measureTooltipElement,
                    offset: [0, -15],
                    positioning: 'bottom-center'
                });
                this.map.addOverlay(measureTooltip);
            },
            /**
             * 加载交互绘制控件函数
             */
            addInteraction(measureType) {
                //绘制交互
                draw = new Draw({
                    source: this.source,//测量绘制层数据源
                    type: measureType,  //几何图形类型
                    style: new Style({
                        //绘制几何图形的样式
                        fill: new Fill({
                            color: 'rgba(255, 255, 255, 0.8)'
                        }),
                        stroke: new Stroke({
                            color: 'rgba(0, 0, 0, 0.5)',
                            lineDash: [10, 10],
                            width: 2
                        }),
                        image: new Circle({
                            radius: 5,
                            stroke: new Stroke({
                                color: 'rgba(0, 0, 0, 0.7)'
                            }),
                            fill: new Fill({
                                color: 'rgba(255, 255, 255, 0.5)'
                            })
                        })
                    })
                });
                //将绘制交互事件添加到地图中
                this.map.addInteraction(draw);

                //创建测量工具提示框
                this.createMeasureTooltip();
                //创建帮助提示框
                this.createHelpTooltip();


                let _this = this
                //绑定交互绘制工具开始绘制的事件
                draw.on('drawstart', (event) => {
                    sketch = event.feature; //绘制的要素
                    var tooltipCoord = event.coordinate;// 绘制的坐标
                    //绑定change事件，根据绘制几何类型得到测量长度值或面积值，并将其设置到测量工具提示框中显示
                    listener = sketch.getGeometry().on('change', (event) => {
                        var geom = event.target;//绘制几何要素
                        var output;
                        if (geom instanceof Polygon) {
                            output = _this.formatArea(geom);//面积值
                            //获取一个在几何体中内部的坐标点
                            tooltipCoord = geom.getInteriorPoint().getCoordinates();//坐标
                        } else if (geom instanceof LineString) {
                            output = _this.formatLength(geom);//长度值
                            //测量长度获取到线的最后一个坐标
                            tooltipCoord = geom.getLastCoordinate();//坐标
                        }
                        measureTooltipElement.innerHTML = output;//将测量值设置到测量工具提示框中显示
                        measureTooltip.setPosition(tooltipCoord);//设置测量工具提示框的显示位置
                    });
                });
                //绑定交互绘制工具结束绘制的事件
                draw.on('drawend', (event) => {
                    measureTooltipElement.className = 'tooltip tooltip-static'; //设置测量提示框的样式
                    measureTooltip.setOffset([0, -7]);
                    sketch = null; //置空当前绘制的要素对象
                    measureTooltipElement = null; //置空测量工具提示框对象
                    _this.createMeasureTooltip();//重新创建一个测试工具提示框显示结果
                    unByKey(listener);
                });
            },
            /**
             * 测量长度输出
             * @param {ol.geom.LineString} line
             * @return {string}
             */
            formatLength(line) {
                var length;
                //使用测地学方法测量
                var sourceProj = this.map.getView().getProjection(); //地图数据源投影坐标系
                length = sphere.getLength(line, {"projection": sourceProj, "radius": 6378137});

                var output;
                if (length > 100) {
                    output = (Math.round(length / 1000 * 100) / 100) + ' ' + 'km'; //换算成KM单位
                } else {
                    output = (Math.round(length * 100) / 100) + ' ' + 'm'; //m为单位
                }
                return output;//返回线的长度
            },
            /**
             * 测量面积输出
             * @param {ol.geom.Polygon} polygon
             * @return {string}
             */
            formatArea(polygon) {
                var area;
                //使用测地学方法测量
                var sourceProj = this.map.getView().getProjection();//地图数据源投影坐标系
                var geom = (polygon.clone().transform(sourceProj, 'EPSG:4326')); //将多边形要素坐标系投影为EPSG:4326
                area = Math.abs(sphere.getArea(geom, {"projection": sourceProj, "radius": 6378137})); //获取面积
                var output;
                if (area > 10000) {
                    output = (Math.round(area / 1000000 * 100) / 100) + ' ' + 'km<sup>2</sup>'; //换算成KM单位
                } else {
                    output = (Math.round(area * 100) / 100) + ' ' + 'm<sup>2</sup>';//m为单位
                }
                return output; //返回多边形的面积
            }
        }

    }
</script>

<style scoped>
    #map {
        width: 100%;
        height: 100%;
    }

    .MapTool {
        position: absolute;
        top: .5em;
        right: .5em;
        z-index: 9999;
    }

    /**
      * 提示框的样式信息
      */
    #map >>> .tooltip {
        position: relative;
        background: rgba(0, 0, 0, 0.5);
        border-radius: 4px;
        color: white;
        padding: 4px 8px;
        opacity: 0.7;
        white-space: nowrap;
    }

    #map >>> .tooltip-measure {
        opacity: 1;
        font-weight: bold;
    }

    #map >>> .tooltip-static {
        background-color: #ffcc33;
        color: black;
        border: 1px solid white;
    }

    #map >>> .tooltip-measure:before, .tooltip-static:before {
        border-top: 6px solid rgba(0, 0, 0, 0.5);
        border-right: 6px solid transparent;
        border-left: 6px solid transparent;
        content: "";
        position: absolute;
        bottom: -6px;
        margin-left: -7px;
        left: 50%;
    }

    #map >>> .tooltip-static:before {
        border-top-color: #ffcc33;
    }
</style>